#ifndef _INIT_H
#define _INIT_H

#include <compiler.h>

typedef int (*initcall_t)(void);

#define __initcall(level, fn)								\
	initcall_t __initcall_##fn##level						\
		__always_unused __section(.__initcall##level) = fn

#define earliest0_initcall(fn)	__initcall(0, fn)
#define earliest1_initcall(fn)	__initcall(1, fn)
#define earliest2_initcall(fn)	__initcall(2, fn)

#define early0_initcall(fn)		__initcall(3, fn)
#define early1_initcall(fn)		__initcall(4, fn)
#define early2_initcall(fn)		__initcall(5, fn)

#define core0_initcall(fn)		__initcall(6, fn)
#define core1_initcall(fn)		__initcall(7, fn)
#define core2_initcall(fn)		__initcall(8, fn)

#define late0_initcall(fn)		__initcall(9, fn)
#define late1_initcall(fn)		__initcall(10, fn)
#define late2_initcall(fn)		__initcall(11, fn)

extern initcall_t __initcalls_earliest_start[], __initcalls_earliest_end[];

extern initcall_t __initcalls_early_start[], __initcalls_early_end[];

extern initcall_t __initcalls_core_start[], __initcalls_core_end[];

extern initcall_t __initcalls_late_start[], __initcalls_late_end[];

#define for_each_earliest_initcall(fn)							\
	for ((fn) = __initcalls_earliest_start; (fn) < __initcalls_earliest_end; (fn)++)

#define for_each_early_initcall(fn)							\
	for ((fn) = __initcalls_early_start; (fn) < __initcalls_early_end; (fn)++)

#define for_each_core_initcall(fn)							\
	for ((fn) = __initcalls_core_start; (fn) < __initcalls_core_end; (fn)++)

#define for_each_late_initcall(fn)							\
	for ((fn) = __initcalls_late_start; (fn) < __initcalls_late_end; (fn)++)

typedef void (*exitcall_t)(void);

#define __exitcall(level, fn)								\
	exitcall_t __exitcall_##fn##level						\
		__always_unused __section(.__exitcall##level) = fn

#define exitcall0(fn)		__exitcall(0, fn)
#define exitcall1(fn)		__exitcall(1, fn)
#define exitcall2(fn)		__exitcall(2, fn)

extern exitcall_t __exitcalls_start[], __exitcalls_end[];

#define for_each_exitcall(fn)							\
	for ((fn) = __exitcalls_start; (fn) < __exitcalls_end; (fn)++)

#endif /* _INIT_H */

